﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;


using CustomDrawnFileDialog;
using OpenFileDialog = CustomDrawnFileDialog.CustomFileDialog;

using LowLevelGraphics.CustomControls;
using LowLevelGraphics;
using LowLevelGraphics.ColorSpaces;

using ImageRecognition2.MouseImageTools;

namespace ImageRecognition2.Forms
{
    //TODO: CUT / CROP Image
    //            if (m_bCutImage)
    //{
    //    e.Graphics.DrawRectangle(Pens.Blue, m_CutRectangle);
    //}
    //if (m_bCutImage)
    //{
    //    m_CutRectangle = RectangleHelpers.CalcRectangle(m_ptStart, m_ptEnd);
    //}

    public partial class FormChild : Form
    {
        public delegate void ColorChangedEventHandler(object sender, ColorChangedEventArgs e);
        public delegate void PixelClickedEventHandler(object sender, PixelClickedEventArgs e);

        public static event ColorChangedEventHandler ColorChangedEvent = null;
        public static event PixelClickedEventHandler PixelClickedEvent = null;

        protected int m_nChildNumber = 0;
        protected static int nStaticChildNumber = 0;
        protected static string sStaticChildName = string.Empty;
        protected SelectablePictureBox m_PictureBox = null;
        protected Bitmap m_Bitmap = null;
        protected bool m_bCutImage = false;
        protected bool m_bMouseDown = false;
        protected Point m_ptStart = new Point(-1, -1);
        protected Point m_ptEnd = new Point(-1, -1);
        protected Rectangle m_CutRectangle = Rectangle.Empty;

        protected List<ColorRect> m_aColorRect = new List<ColorRect>();
        protected Color m_ConcretePixelColor = Color.Transparent;

        protected Point m_ptLocation = Point.Empty;
        protected string m_sInternalName = string.Empty;

        private string m_sPicFullQualifiedName = string.Empty;

        private Dictionary<Type, MouseImageToolBase> m_aTool = new Dictionary<System.Type, MouseImageToolBase>();

        /// <summary>
        /// Default constructor
        /// </summary>
        public FormChild()
        {
            InitializeComponent();

            AssemblyHelperTool<MouseImageToolBase> aTool = new AssemblyHelperTool<MouseImageToolBase>("ImageRecognition2.MouseImageTools", "Tool", new object[]{pictureBox1});
            for (int i = 0; i < aTool.Items.Count; i++)
            {
                this.m_aTool.Add(aTool.Items[i].GetType(), aTool.Items[i]);
            }

            this.ActivateTool(typeof(SelectionTool));

            this.AllowDrop = true;
            this.pictureBox1.AllowDrop = true;
            this.pictureBox1.DragEnter += new DragEventHandler(FormChild_DragEnter);
            this.pictureBox1.DragDrop += new DragEventHandler(FormChild_DragDrop);
            this.pictureBox1.DragOver += new DragEventHandler(pictureBox1_DragOver);
            this.pictureBox1.DragLeave += new EventHandler(pictureBox1_DragLeave);
            //            this.pictureBox1.Drag
            nStaticChildNumber++;
            m_nChildNumber = nStaticChildNumber;
            sStaticChildName = "Child_" + nStaticChildNumber;


            this.Text = sStaticChildName;
            m_sInternalName = sStaticChildName;

            this.pictureBox1.AllowDrop = true;

            this.pictureBox1.Paint += new PaintEventHandler(pictureBox1_Paint);
            this.pictureBox1.DoubleClick += new EventHandler(pictureBox1_DoubleClick);
            this.pictureBox1.MouseMove += new MouseEventHandler(pictureBox1_MouseMove);
            this.pictureBox1.BackgroundImageLayout = ImageLayout.Zoom;
            this.pictureBox1.MouseDown += new MouseEventHandler(pictureBox1_MouseDown);
            this.pictureBox1.MouseUp += new MouseEventHandler(pictureBox1_MouseUp);

            this.pictureBox1.Click += new EventHandler(pictureBox1_Click);
            this.pictureBox1.BackgroundImage = m_Bitmap;
        }

        /// <summary>
        /// Gets or sets the loaded picture full qualified path.
        /// </summary>
        /// <value>The loaded picture full qualified path.</value>
        public string LoadedPictureFullQualifiedPath
        {
            get { return m_sPicFullQualifiedName; }
            set { m_sPicFullQualifiedName = value; }
        }

        void pictureBox1_DragLeave(object sender, EventArgs e)
        {
        }

        void pictureBox1_DragOver(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

        void FormChild_DragEnter(object sender, DragEventArgs e)
        {
            // Check if the Dataformat of the data can be accepted
            // (we only accept file drops from Explorer, etc.)
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy; // Okay              
            }
            else
            {
                e.Effect = DragDropEffects.None; // Unknown data, ignore it
            }

        }

        /// <summary>
        /// Handles the DragDrop event of the FormChild control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
        void FormChild_DragDrop(object sender, DragEventArgs e)
        {
            // Handle FileDrop data.
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                // Assign the file names to a string array, in 
                // case the user has selected multiple files.
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                try
                {
                    // Assign the first image to the picture variable.
                    LoadPicture(files[0]);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return;
                }
            }
        }

        /// <summary>
        /// Handles the Click event of the pictureBox1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void pictureBox1_Click(object sender, EventArgs e)
        {
            OnPixelClicked(new PixelClickedEventArgs(m_ptLocation, m_ConcretePixelColor));
        }

        /// <summary>
        /// Return child number
        /// </summary>
        public int ChildNumber
        {
            get { return m_nChildNumber; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            m_bMouseDown = false;
            if (m_bCutImage)
            {
                m_ptEnd = e.Location;
                m_bCutImage = false;
                Rectangle rectangle = RectangleHelpers.CalcRectangle(m_ptStart, m_ptEnd);
                this.pictureBox1.BackgroundImage = BitmapFunctions.GetPicturePart(this.pictureBox1.BackgroundImage, rectangle);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && m_bCutImage)
            {
                if (m_bMouseDown)
                {
                    m_ptStart = e.Location;
                }
            }
            if (e.Button == MouseButtons.Right)
            {
                Bitmap bitmap = (Bitmap)this.pictureBox1.BackgroundImage;
                if (bitmap == null) return;
                //Rectangle rectBlob = ColorBlobExtractor.BlobRectangle(bitmap, e.Location, 3, 3, 3);

                //if (rectBlob.Height > 0 && rectBlob.Width > 0)
                //{
                //    m_aColorRect.Add(new ColorRect(Color.Red, rectBlob));
                //}

                pictureBox1.Invalidate();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        [DebuggerStepThrough]
        void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            //Graphics g = e.Graphics;
        }

        /// <summary>
        /// Load a picture into this picture box
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            LoadPicture(null);
        }

        /// <summary>
        /// Loads the picture.
        /// </summary>
        /// <param name="_sFileName">Name of the _s file.</param>
        public void LoadPicture(string _sFileName)
        {
            string sFileName = MainFormSingleton.Instance.LoadPicture(_sFileName);
            this.m_sInternalName = sStaticChildName = "Child_" + nStaticChildNumber + " [" + _sFileName + "]";
            this.Text = this.m_sInternalName;
        }

        /// <summary>
        /// Mouse move
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (MainFormSingleton.ActivePictureBox == null || MainFormSingleton.ActivePictureBox.BackgroundImage == null)
                return;

            m_ptLocation = e.Location;

            //TODO: search for solution if more than one screen!!!
            //m_ConcretePixelColor = Core.GetPixelColorFromScreen(); //get concrete pixel color
            //OnColorChanged(new ColorChangedEventArgs(m_ConcretePixelColor));
            //YCbCr ycbcr = new YCbCr(m_ConcretePixelColor);
            //MainFormSingleton.Instance.toolStripStatusLabel1.Text = e.Location.ToString() + " " + m_ConcretePixelColor.ToString() + " " + ycbcr.ToString();
        }

        /// <summary>
        /// Called when [color changed].
        /// </summary>
        protected virtual void OnColorChanged(ColorChangedEventArgs e)
        {
            if (ColorChangedEvent != null)
            {
                ColorChangedEvent(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="E:PixelClicked"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        protected virtual void OnPixelClicked(PixelClickedEventArgs e)
        {
            if (PixelClickedEvent != null)
            {
                PixelClickedEvent(this, e);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_tType"></param>
        internal void ActivateTool(System.Type _tType)
        {
            this.ActivateTool(_tType, false);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="_tType"></param>
        /// <param name="_bSuspendOtherTools"></param>
        internal void ActivateTool(System.Type _tType, bool _bSuspendOtherTools)
        {
            foreach (KeyValuePair<Type, MouseImageToolBase> dict in this.m_aTool)
            {
                MouseImageToolBase toolBase = dict.Value;
                if (_bSuspendOtherTools)
                {
                    toolBase.Deactivate();
                }
                if (toolBase.GetType() == _tType)
                {
                    toolBase.Control = pictureBox1;
                    toolBase.Activate();
                }
            }
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return this.m_sInternalName;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class ColorChangedEventArgs
    {
        protected Color m_Color = Color.Transparent;

        /// <summary>
        /// Initializes a new instance of the <see cref="ColorChangedEventArgs"/> class.
        /// </summary>
        /// <param name="_color">The _color.</param>
        public ColorChangedEventArgs(Color _color)
        {
            m_Color = _color;
        }

        /// <summary>
        /// Gets or sets the color.
        /// </summary>
        /// <value>The color.</value>
        public Color Color
        {
            get { return m_Color; }
            set { m_Color = value; }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class PixelClickedEventArgs : ColorChangedEventArgs
    {
        protected Point m_ptLocation = Point.Empty;

        /// <summary>
        /// Initializes a new instance of the <see cref="PixelClickedEventArgs"/> class.
        /// </summary>
        public PixelClickedEventArgs(Point _ptLocation, Color _color)
            : base(_color)
        {
            m_ptLocation = _ptLocation;
        }
    }
}
